using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Newtonsoft.Json;
using UnityEngine;

/// <summary>
/// 数据分析器
/// </summary>
public class StockDataAnalysis : BatchProcessor
{
    public const int defaultFromYear = 2021;
    /// <summary>
    /// 筛选从哪年开始的数据
    /// </summary>
    public int fromYear = defaultFromYear;
    /// <summary>
    /// 连续上涨几天判断为上涨波段
    /// </summary>
    public int goUpRangeCheckDays = 5;
    public static string dataOutputDir => Application.dataPath + "/OutputData/";
    
    [NonSerialized]
    private StockAllData m_stockAllData;
    StockAllData testStockAllData
    {
        get
        {
            if (m_stockAllData == null || m_stockAllData.stockTransitions == null)
            {
                m_stockAllData = StocksDataController.instance.GetStockAllData(testStock,fromYear);
            }
            return m_stockAllData;
        }
    }
    public int analysisStockCount = 10;
    
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log($"stock:{testStock} transitions count:{testStockAllData?.stockTransitions?.Count}");
    }

    //public Action<float> onCalStatisticProgress;
    //public Action onCalStatisticEnd;
    [ContextMenu("CalStockStatistic")]
    public void CalStockStatistic()
    {
        //StartCoroutine(CalAndSaveStocksStatistic());
        
        DoActionToAllStocks(CalAndSaveStocksStatistic);
    }

    void CalAndSaveStocksStatistic(StockData stock)
    {
        if(!Directory.Exists(StocksDataController.stocksStatisticDir( fromYear)))
        {
            Directory.CreateDirectory(StocksDataController.stocksStatisticDir(fromYear));
        }
        
        var stockAllData = StocksDataController.instance.GetStockAllData(stock.dm, fromYear);
        if (stockAllData == null || stockAllData.stockChengJiaoFenBu == null)
            return;

        double hslTotal = 0;
        double hslBeginTotal = 0;
        double hslEndTotal = 0;
        foreach (var chengJiaoFenBuData in stockAllData.stockChengJiaoFenBu)
        {
            hslTotal += chengJiaoFenBuData.hsl;
        }

        var goUpRanges = FindGoUp5DaysRange(stockAllData, goUpRangeCheckDays);
        int count = 0;
        foreach (var transitionsRange in goUpRanges.transitionsRanges)
        {
            var first = transitionsRange.transitions[0];
            var last = transitionsRange.transitions[^1];
            var firstDate = DateTime.Parse(first.d);
            var lastDate = DateTime.Parse(last.d);

            ChengJiaoFenBuData beginData = stockAllData.GetChengJiaoFenBuWithDay(firstDate);
            if (beginData == null)
            {
                Debug.LogError($"cannot find chengjiaofenbu on beginDate:{firstDate}");
                continue;
            }

            hslBeginTotal += beginData.hsl;

            ChengJiaoFenBuData endData = stockAllData.GetChengJiaoFenBuWithDay(lastDate);
            if (endData == null)
            {
                Debug.LogError($"cannot find chengjiaofenbu on endDate:{lastDate}");
            }

            if (endData != null)
                hslEndTotal += endData.hsl;

            count++;
        }

        StockStatistic stockStatistic = new StockStatistic();
        //stockStatistic.goUpRanges = goUpRanges;
        stockStatistic.stockCode = stock.dm;
        stockStatistic.averHsl = hslTotal / stockAllData.stockChengJiaoFenBu.Count;
        stockStatistic.averHslOnBeginGoUp = hslBeginTotal / count;
        stockStatistic.averHslOnBeginGoDown = hslEndTotal / count;

        string str = JsonConvert.SerializeObject(stockStatistic);
        Debug.Log(str);
        File.WriteAllText(StocksDataController.stocksStatisticPath(fromYear, stock.dm), str);
    }

    /// <summary>
    /// 分析所有股票的上涨波段数据，并把平均换手率等统计结果保存到本地
    /// </summary>
    /// <returns></returns>
    IEnumerator CalAndSaveStocksStatistic()
    {
        if (!Directory.Exists(StocksDataController.stocksStatisticDir(fromYear)))
        {
            Directory.CreateDirectory(StocksDataController.stocksStatisticDir(fromYear));
        }

        int total = 0;
        int hslLowerOnBeginGoUp = 0;
        int index = 0;
        var allStocks = StocksDataController.instance.allStocks;
        foreach (var stock in allStocks)
        {
            index++;

            CalAndSaveStocksStatistic(stock);
            
            var stockStatistic =
                JsonConvert.DeserializeObject<StockStatistic>(
                    File.ReadAllText(StocksDataController.stocksStatisticPath(fromYear, stock.dm)));
            
            if(stockStatistic.averHslOnBeginGoUp < stockStatistic.averHsl)
                hslLowerOnBeginGoUp++;
            
            total++;

            //onCalStatisticProgress?.Invoke((float) index / allStocks.Count);
            onProgress?.Invoke((float) index / allStocks.Count);
            yield return null;
            //Thread.Sleep(5);
        }

        onEnd?.Invoke("");
        float rate = (float)hslLowerOnBeginGoUp / total;
        string content = $"total:{total}, hslLowerOnBeginGoUp:{hslLowerOnBeginGoUp}, 换手率大都低于平均换手率的比率：{rate}";
        Debug.LogError(content);
    }


    private int m_curIndex;
    public List<string> testStocks;
    [ContextMenu("AnalysisAllStocksGoUp5DaysRange")]
    void AnalysisAllStocksGoUp5DaysRange()
    {
        m_curIndex = 0;
        testStocks = StocksDataController.instance.allStocks.GetRange(0, analysisStockCount).Map(e=>e.dm).AsList();
        m_GoUpRangeResults = new List<ZhuLiZiJinOfGoUpRangeResult>();
        AnalysisStocksGoUp5DaysRange();
    }

    private List<ZhuLiZiJinOfGoUpRangeResult> m_GoUpRangeResults;

    /// <summary>
    /// 分析所有上涨波段的数据
    /// </summary>
    void AnalysisStocksGoUp5DaysRange()
    {
        if (m_curIndex >= testStocks.Count)
        {
            Debug.Log("结束");
            int totalRangeCount = 0; //上涨波段数
            double zljlrUpOnBegin = 0; //开始上涨时主力净流入正
            double zljlrlAverTotal = 0; //开始上涨时平均主力净流入率
            double hslBeginAver = 0; //开始上涨时平均换手率
            double zljlrDownOnEnd = 0; //开始下跌时主力净流入负
            double zljlrlAverOnEnd = 0; //开始下跌时主力净流入率
            double hslEndTotal = 0; //开始下跌时平均换手率
            double hslBi = 0;
            foreach (var goUpRangeResult in m_GoUpRangeResults)
            {
                totalRangeCount += goUpRangeResult.totalRangeCount;
                zljlrUpOnBegin += goUpRangeResult.zljlrUpOnBegin;
                zljlrlAverTotal += goUpRangeResult.zljlrlAver;
                hslBeginAver += goUpRangeResult.hslBeginAver;
                zljlrDownOnEnd += goUpRangeResult.zljlrDownOnEnd;
                zljlrlAverOnEnd += goUpRangeResult.zljlrlAverOnEnd;
                hslEndTotal += goUpRangeResult.hslEndTotal;
                hslBi += goUpRangeResult.hslEndBiBegin;

                double averZljlrUpOnBeginRate = zljlrUpOnBegin / totalRangeCount;
                double zljlrlAver = zljlrlAverTotal / m_GoUpRangeResults.Count;
                double averHslBeginAver = hslBeginAver / m_GoUpRangeResults.Count;
                double averZljlrDownOnEnd = zljlrDownOnEnd / totalRangeCount;
                double averZljlrlAverOnEnd = zljlrlAverOnEnd / m_GoUpRangeResults.Count;
                double averhHlEndTotal = hslEndTotal / m_GoUpRangeResults.Count;
                double averHslBi = hslBi / m_GoUpRangeResults.Count;
                Debug.LogError(
                    $"开始上涨时，近{zlday}日主力净流入大于0的比例为：{averZljlrUpOnBeginRate}, 平均主力净流入率为：{zljlrlAver}, 平均换手率 {averHslBeginAver}" +
                    $"\n开始下跌时，主力净流出小于0的比例为{averZljlrDownOnEnd}，平均主力净流入率:{averZljlrlAverOnEnd}, 平均换手率为：{averhHlEndTotal}, 换手率尾始比：{averHslBi}");

                return;
            }

            string stock = testStocks[m_curIndex];
            var stockData = StocksDataController.instance.GetStockAllData(stock, fromYear);
            var result = GetGoUp5DaysRangeAnalysisResult(stockData);
            m_GoUpRangeResults.Add(result);

            m_curIndex++;
            DoActionDelay.DelayAction(0.02f, AnalysisStocksGoUp5DaysRange);
        }
    }

    /// <summary>
    /// 获取股票的所有上涨波段
    /// </summary>
    /// <param name="stockAllData"></param>
    /// <param name="goUpRangeDays"></param>
    /// <returns></returns>
    StockTransitionsRanges FindGoUp5DaysRange(StockAllData stockAllData,int goUpRangeDays)
    {
        var goUp5DayRanges = new StockTransitionsRanges();
        goUp5DayRanges.stockCode = stockAllData.stockData.dm;
        goUp5DayRanges.transitionsRanges = new List<TransitionsRange>();
        
        int continueGoUpCount = 0;
        var transitions = stockAllData.stockTransitions;
        for (int i = 1; i < transitions.Count; i++)
        {
            var cur = transitions[i];
            var pre = transitions[i - 1];

            bool goUp = cur.c > pre.c;
            if (goUp)
                continueGoUpCount++;
            else
            {
                if (continueGoUpCount >= goUpRangeDays)
                {
                    TransitionsRange range = new TransitionsRange();
                    range.transitions = new List<TransitionData>();
                    for (int j = i - 1 - continueGoUpCount; j <= i - 1; j++)
                    {
                        range.transitions.Add(transitions[j]);
                    }
                    //Debug.Log($"找到一个上涨波段：{continueGoUpCount},from {range.transitions[0].d} to {range.transitions[^1].d}");
                    goUp5DayRanges.transitionsRanges.Add(range);
                }
                continueGoUpCount = 0;
            }
        }
        
        Debug.Log($"{goUp5DayRanges.stockCode}上涨超过5天的阶段有：{goUp5DayRanges.transitionsRanges.Count}个");
        //Debug.Log($"它们是:\n{JsonConvert.SerializeObject(goUp5DayRanges)}");
        return goUp5DayRanges;
    }
    ZhuLiZiJinOfGoUpRangeResult GetGoUp5DaysRangeAnalysisResult(StockAllData stockAllData)
    {
        var goUp5DayRanges = FindGoUp5DaysRange(stockAllData,goUpRangeCheckDays);
        return AnalysisZhuLiZiJinOfGoUpRanges(goUp5DayRanges);
    }

    int zlday = 3;
    private static string goUp5DaysJieDuanZhuLiOutputDataDir => dataOutputDir + "GoUp5DaysJieDuanZhuLi/";
    /// <summary>
    /// 分析上涨波段的数据
    /// </summary>
    /// <param name="goUp5DayRanges"></param>
    /// <returns></returns>
    ZhuLiZiJinOfGoUpRangeResult AnalysisZhuLiZiJinOfGoUpRanges(StockTransitionsRanges goUp5DayRanges)
    {
        if (!Directory.Exists(goUp5DaysJieDuanZhuLiOutputDataDir))
            Directory.CreateDirectory(goUp5DaysJieDuanZhuLiOutputDataDir);

        int totalRangeCount = 0;//goUp5DayRanges.transitionsRanges.Count;

        int zljlrUpOnBegin = 0;
        int zljlrDownOnBegin = 0;
        int zljlrUpOnEnd = 0;
        int zljlrDownOnEnd = 0;
        double hslBeginTotal = 0; 
        double hslEndTotal = 0;
        double zljlrlOnBeginTotal = 0;
        double zljlrlOnEndTotal = 0;
        
        int checkDayBefore = 8;
        int checkDayAfter = 4;

        foreach (var range in goUp5DayRanges.transitionsRanges)
        {
            string content = JsonConvert.SerializeObject(range);
            
            var first = range.transitions[0];
            var last = range.transitions[^1];

            var firstDate = DateTime.Parse(first.d);
            var lastDate = DateTime.Parse(last.d);
            int rangeInt = lastDate.DayOfYear - firstDate.DayOfYear;
            Debug.Log($"上涨阶段【{firstDate},{lastDate}】,firstDate.DayOfYear:{firstDate.DayOfYear}, lastDate.DayOfYear:{lastDate.DayOfYear}");

            //阶段主力
            List<JieDuanZhuLiData> jieDuanZhuLiDatas = new List<JieDuanZhuLiData>();
            //资金流入
            List<ZiJinLiuRuData> zijinliuruDatas = new List<ZiJinLiuRuData>();
            //成交分布
            List<ChengJiaoFenBuData> chengjiaofenbuDatas = new List<ChengJiaoFenBuData>();
            
            for (int i = -checkDayBefore; i <= rangeInt + checkDayAfter; i++)
            {
                DateTime checkDate = firstDate.AddDays(i);

                var jieduanzhuli = testStockAllData.GetJieDuanZhuLiWithDay(checkDate);
                if (jieduanzhuli != null)
                    jieDuanZhuLiDatas.Add(jieduanzhuli);
                else
                    continue; //Debug.Log($"找不到{checkDate}的阶段主力动向数据");
                
                var zijinliuru = testStockAllData.GetZiJinLiuRuWithDay(checkDate);
                if (zijinliuru != null)
                    zijinliuruDatas.Add(zijinliuru);
                else
                    continue;//Debug.Log($"找不到{checkDate}的阶段资金流入数据");
                
                var chengjiaofenbu = testStockAllData.GetChengJiaoFenBuWithDay(checkDate);
                if (chengjiaofenbu != null)
                    chengjiaofenbuDatas.Add(chengjiaofenbu);
                else
                    continue;//Debug.Log($"找不到{checkDate}的阶段成交分布数据");

                if (i == 0)
                {
                    double jlr = 0,jlrl = 0;
                    if(zlday == 10) {jlr = jieduanzhuli.jlr10;jlrl = jieduanzhuli.jlrl10;}
                    else if(zlday == 5){ jlr = jieduanzhuli.jlr5;jlrl = jieduanzhuli.jlrl5;}
                    else if(zlday == 3) {jlr = jieduanzhuli.jlr3;jlrl = jieduanzhuli.jlrl3;}
                    
                    Debug.Log($"开始上涨这天，近{zlday}日主力净流入：{jlr}, 近{zlday}日主力净流入率：{jlrl},当天主力净流入：{zijinliuru.zljlr},当天主力净流入率：{zijinliuru.zljlrl}, 当天资金流入：{zijinliuru.jlr}, 换手率：{chengjiaofenbu.hsl}");
                    if (zlday == 10 && jieduanzhuli.jlr10 > 0 || zlday == 5 && jieduanzhuli.jlr5 > 0 || zlday == 3 && jieduanzhuli.jlr3 > 0)
                        zljlrUpOnBegin++;
                    else
                        zljlrDownOnBegin++;
                    hslBeginTotal += chengjiaofenbu.hsl;
                    zljlrlOnBeginTotal += jlrl;
                }
                else if (i == rangeInt)
                {
                    totalRangeCount++;
                    Debug.Log($"开始下跌这天，近三日主力净流入：{jieduanzhuli.jlr3}, 近三日主力净流入率：{jieduanzhuli.jlrl3},当天主力净流入：{zijinliuru.zljlr},当天主力净流入率：{zijinliuru.zljlrl},  当天资金流入：{zijinliuru.jlr}, 换手率：{chengjiaofenbu.hsl}");

                    if (zijinliuru.jlr < 0)  
                    //if (jieduanzhuli.jlr3 < 0)
                        zljlrDownOnEnd++;
                    else zljlrUpOnEnd++;
                    
                    hslEndTotal += chengjiaofenbu.hsl;
                    zljlrlOnEndTotal += jieduanzhuli.jlrl3;// zijinliuru.jlrl;//zijinliuru.zljlrl;// jieduanzhuli.jlrl3;// 
                }
            }
            
            content += "\n\n\n";
            string zhuliStr = JsonConvert.SerializeObject(jieDuanZhuLiDatas);
            content += zhuliStr;
            //Debug.Log($"这阶段的主力动向数据是：{zhuliStr}");
            
            content += "\n\n\n";
            string zijinliuruStr = JsonConvert.SerializeObject(zijinliuruDatas);
            content += zijinliuruStr;
            //Debug.Log($"这阶段的资金流入数据是：{zijinliuruStr}");
            
            content += "\n\n\n";
            string chengjiaofenbuStr = JsonConvert.SerializeObject(chengjiaofenbuDatas);
            content += chengjiaofenbuStr;
            //Debug.Log($"这阶段的成交分布数据是：{chengjiaofenbuStr}");
            
            string path = goUp5DaysJieDuanZhuLiOutputDataDir +
                          $"{goUp5DayRanges.stockCode}_{StockAllData.GetDateKey(firstDate)}_{StockAllData.GetDateKey(lastDate)}.json";
            //File.WriteAllText(path,content);
        } 
        double zljlrlAver = zljlrlOnBeginTotal / totalRangeCount;
        double zljlrlAverOnEnd = zljlrlOnEndTotal / totalRangeCount;
        double hslBeginAver = hslBeginTotal / totalRangeCount;
        double hslEndAver = hslEndTotal / totalRangeCount;
        double hslEndBiBegin = hslEndAver / hslBeginAver;
        Debug.LogError($"共有{totalRangeCount}个上涨波段，开始上涨时，近{zlday}日主力净流入大于0的有{zljlrUpOnBegin}次，反之{zljlrDownOnBegin}次,近{zlday}日平均主力净流入率为：{zljlrlAver},平均换手率为：{hslBeginAver}");
        Debug.LogError($"开始下跌时，主力净流出小于0的有{zljlrDownOnEnd}次，反之{zljlrUpOnEnd}次，平均主力净流入率:{zljlrlAverOnEnd}, 平均换手率为：{hslEndAver}, 换手率与开始的比率为：{hslEndBiBegin}");

        ZhuLiZiJinOfGoUpRangeResult result = new ZhuLiZiJinOfGoUpRangeResult();
        result.totalRangeCount = totalRangeCount;
        result.zljlrUpOnBegin = zljlrUpOnBegin;
        result.zljlrlAver = zljlrlAver;
        result.hslBeginAver = hslBeginAver;
        result.zljlrDownOnEnd = zljlrDownOnEnd;
        result.zljlrlAverOnEnd = zljlrlAverOnEnd;
        result.hslEndTotal = hslEndAver;
        result.hslEndBiBegin = hslEndBiBegin;
        return result;
    }

    
    // Update is called once per frame
    void Update()
    {
        
    }
    
    #region test
    
    public string testStock = "000001";
    
    [ContextMenu("FindTestStockGoUp5DaysRange")]
    void FindTestStockGoUp5DaysRange()
    {
        GetGoUp5DaysRangeAnalysisResult(this.testStockAllData);
    }
    
    [ContextMenu("TestGetZhuliZiJin")]
    void TestGetZhuliZiJin()
    {
        var firstTrans = testStockAllData.stockTransitions[1];
        var date = DateTime.Parse(firstTrans.d);
        Debug.Log($"firstTrans.d:{firstTrans.d} , date:{date} ");
        var jieduanzhuli = testStockAllData.GetJieDuanZhuLiWithDay(date);
        Debug.Log($"jieduanzhuli:{JsonConvert.SerializeObject(jieduanzhuli)}");
    }

    #endregion

    protected override void onCompleted()
    {
        base.onCompleted();
    }
}
